from lxml import etree
from copy import deepcopy
from collections import defaultdict
import can_message_tool as cmt
from enum import Enum, auto

can_xdm_file_path = "./xdm_files/Can.xdm"

class gl0906_CanID_Msg_Type(Enum):
    EXTENDED = 0
    MIXED = auto()
    STANDARD = auto()

g_canid_msg_type_dict = {
    gl0906_CanID_Msg_Type.EXTENDED: 'EXTENDED',
    gl0906_CanID_Msg_Type.MIXED: 'MIXED',
    gl0906_CanID_Msg_Type.STANDARD: 'STANDARD'
}

class gl0906_xml_parser:
    def __init__(self, xml_file_path):
        # Initialize xml file variables
        self.xml_file_path = xml_file_path
        self.tree = None
        self.root = None
        self.nsmap = None
        # Initialize Can Model variables
        self.cntl_hond = cmt.gl0906_can_controller_hw_obj_num()

        # Initialize functions
        self.xml_init_parse()
    def xml_init_parse(self):
        # with open(self.xml_file_path, 'rb') as file:
        #     xml_content = file.read()

        # print(xml_content)

        # Parse XML File
        parser = etree.XMLParser(remove_blank_text=False)
        self.tree = etree.parse(self.xml_file_path, parser)
        # self.tree = etree.fromstring(xml_content)
        self.root = self.tree.getroot()

        # Get root tag and basic info
        # self.root_tag = self.root.tag
        # self.root_attrib = self.root.attrib

        # Get Namespaces
        self.nsmap = dict([
        node for _, node in etree.iterparse(self.xml_file_path, events=['start-ns'])
        ])

    def handle_can_hwobj_CanIdType(self, cntl, number, type):
        handle_id = 0
        if cmt.Controller.CanController_BCAN == cntl:
            handle_id = number
        elif cmt.Controller.CanController_CCAN == cntl:
            handle_id += self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_BCAN]['receive']
            handle_id += number
        elif cmt.Controller.CanController_PCAN == cntl:
            handle_id += self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_BCAN]['receive']
            handle_id += self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_CCAN]['receive']
            handle_id += number
        elif cmt.Controller.CanController_ACAN == cntl:
            handle_id += self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_BCAN]['receive']
            handle_id += self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_CCAN]['receive']
            handle_id += self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_PCAN]['receive']
            handle_id += number
        elif cmt.Controller.CanController_DCAN == cntl:
            handle_id += self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_BCAN]['receive']
            handle_id += self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_CCAN]['receive']
            handle_id += self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_PCAN]['receive']
            handle_id += self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_ACAN]['receive']
            handle_id += number
        else:
            print("Error: Controller not found")
            return
        # print("Modify CanHardwareObject_" + str(handle_id) + " to " + g_canid_msg_type_dict[type])
        can_hwo_elem = self.root.find(".//d:lst[@name='CanHardwareObject']", self.nsmap)
        elems = can_hwo_elem.findall("d:ctr", self.nsmap)
        for elem in elems:
            can_object_id = elem.find("d:var[@name='CanObjectId']", self.nsmap)
            if handle_id == int(can_object_id.attrib['value']):
                can_id_type = elem.find("d:var[@name='CanIdType']", self.nsmap)
                can_id_type.set("value", g_canid_msg_type_dict[type])
                print("Modify CanHardwareObject_" + str(handle_id) + " to " + g_canid_msg_type_dict[type])
    def add_can_receive_hwobj_subelements(self, root_elem, src_elem, index):
        new_element = deepcopy(src_elem)
        new_element.attrib['name'] = 'CanHardwareObject_' + str(index)
        can_object_id = new_element.find("d:var[@name='CanObjectId']", self.nsmap)
        can_object_id.attrib['value'] = str(index)
        root_elem.insert(index, new_element)

    def handle_can_hwobj_elements(self):
        can_hwo_elem = self.root.find(".//d:lst[@name='CanHardwareObject']", self.nsmap)
        print(can_hwo_elem.attrib)
        can0_elem = can_hwo_elem.find("d:ctr[@name='CanHardwareObject_31']", self.nsmap)
        # Add 32-63 CanHardwareObject elements
        for index in range(32, self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_BCAN]['receive']):
            self.add_can_receive_hwobj_subelements(can_hwo_elem, can0_elem, index)

        # Update CanHardwareObject index
        can_index = 0
        can0_count = 0
        can1_count = 0
        can2_count = 0
        can3_count = 0
        can4_count = 0
        can5_count = 0
        elems = can_hwo_elem.findall("d:ctr", self.nsmap)
        for elem in elems:
            can_type = elem.find("d:var[@name='CanObjectType']", self.nsmap)
            if "RECEIVE" == can_type.attrib['value']:
                elem.attrib['name'] = 'CanHardwareObject_' + str(can_index)
                can_object_id = elem.find("d:var[@name='CanObjectId']", self.nsmap)
                can_object_id.attrib['value'] = str(can_index)
                can_ref = elem.find("d:ref[@name='CanControllerRef']", self.nsmap)
                if "ASPath:/Can/Can/CanConfigSet/CanController_CAN0" == can_ref.attrib['value']:
                    can0_count += 1
                elif "ASPath:/Can/Can/CanConfigSet/CanController_CAN1" == can_ref.attrib['value']:
                    can1_count += 1
                elif "ASPath:/Can/Can/CanConfigSet/CanController_CAN2" == can_ref.attrib['value']:
                    can2_count += 1
                elif "ASPath:/Can/Can/CanConfigSet/CanController_CAN3" == can_ref.attrib['value']:
                    can3_count += 1
                elif "ASPath:/Can/Can/CanConfigSet/CanController_CAN4" == can_ref.attrib['value']:
                    can4_count += 1
                elif "ASPath:/Can/Can/CanConfigSet/CanController_CAN5" == can_ref.attrib['value']:
                    can5_count += 1
                else:
                    print("CanController not found")
            elif "TRANSMIT" == can_type.attrib['value']:
                can_object_id = elem.find("d:var[@name='CanObjectId']", self.nsmap)
                can_object_id.attrib['value'] = str(can_index)
            else:
                print("CanObjectType not found")

            can_index += 1

        print("Can0:", can0_count, "Can1:", can1_count, "Can2:", can2_count, "Can3:", can3_count, "Can4:", can4_count, "Can5:", can5_count, "Total:", can_index)
        # Modify CanHardwareObject_114 to STANDARD
        self.handle_can_hwobj_CanIdType(cmt.Controller.CanController_DCAN, self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_DCAN]['receive'] - 1, gl0906_CanID_Msg_Type.STANDARD)
    
    def handle_can_hwobj_filter(self, parent_elem, can_filter):
        hwo_filter = parent_elem.find("d:lst[@name='CanHwFilter']", self.nsmap)
        # print(hwo_filter.attrib)
        for filter_elem in hwo_filter.findall("d:ctr", self.nsmap):
            filter_code = filter_elem.find("d:var[@name='CanHwFilterCode']", self.nsmap)
            filter_code.set("value", can_filter.code)
            filter_mask = filter_elem.find("d:var[@name='CanHwFilterMask']", self.nsmap)
            filter_mask.set("value", can_filter.mask)
            # print("CanHwFilterCode:", filter_code.attrib['value'], "CanHwFilterMask:", filter_mask.attrib['value'])
    # Find all can hardware objects elements
    def handle_can_hwobj_filter_elements(self, obj_filter):
        can_hwo_elem = self.root.find(".//d:lst[@name='CanHardwareObject']", self.nsmap)
        print(can_hwo_elem.attrib)
        elems = can_hwo_elem.findall("d:ctr", self.nsmap)
        for elem in elems:
            # print(elem.attrib)
            can_type = elem.find("d:var[@name='CanObjectType']", self.nsmap)
            if "RECEIVE" == can_type.attrib['value']:
                can_object_id = elem.find("d:var[@name='CanObjectId']", self.nsmap)
                can_cntl_id = int(can_object_id.attrib['value'])
                can_ref = elem.find("d:ref[@name='CanControllerRef']", self.nsmap)
                if "ASPath:/Can/Can/CanConfigSet/CanController_CAN0" == can_ref.attrib['value']:

                    self.handle_can_hwobj_filter(elem, obj_filter[cmt.Controller.CanController_BCAN][can_cntl_id])
                elif "ASPath:/Can/Can/CanConfigSet/CanController_CAN1" == can_ref.attrib['value']:
                    can_cntl_id = can_cntl_id - self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_BCAN]['receive']

                    self.handle_can_hwobj_filter(elem, obj_filter[cmt.Controller.CanController_CCAN][can_cntl_id])
                elif "ASPath:/Can/Can/CanConfigSet/CanController_CAN2" == can_ref.attrib['value']:
                    can_cntl_id = can_cntl_id - self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_BCAN]['receive']
                    can_cntl_id = can_cntl_id - self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_CCAN]['receive']

                    self.handle_can_hwobj_filter(elem, obj_filter[cmt.Controller.CanController_PCAN][can_cntl_id])
                elif "ASPath:/Can/Can/CanConfigSet/CanController_CAN3" == can_ref.attrib['value']:
                    can_cntl_id = can_cntl_id - self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_BCAN]['receive']
                    can_cntl_id = can_cntl_id - self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_CCAN]['receive']
                    can_cntl_id = can_cntl_id - self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_PCAN]['receive']

                    self.handle_can_hwobj_filter(elem, obj_filter[cmt.Controller.CanController_ACAN][can_cntl_id])
                elif "ASPath:/Can/Can/CanConfigSet/CanController_CAN4" == can_ref.attrib['value']:
                    can_cntl_id = can_cntl_id - self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_BCAN]['receive']
                    can_cntl_id = can_cntl_id - self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_CCAN]['receive']
                    can_cntl_id = can_cntl_id - self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_PCAN]['receive']
                    can_cntl_id = can_cntl_id - self.cntl_hond.cntl_hon_dict[cmt.Controller.CanController_ACAN]['receive']

                    self.handle_can_hwobj_filter(elem, obj_filter[cmt.Controller.CanController_DCAN][can_cntl_id])
                elif "ASPath:/Can/Can/CanConfigSet/CanController_CAN5" == can_ref.attrib['value']:
                    can5_count += 1
                else:
                    print("CanController not found")
    def write_xml(self):
        with open('./generated/Can.xdm', 'w') as file:
            pass
        self.tree.write('./generated/Can.xdm', pretty_print=True, xml_declaration=False, encoding=None)
        # 保存XML文件，保持原有排版，不增加XML声明
        # new_content = etree.tostring(self.tree, pretty_print=True, xml_declaration=False, encoding='unicode')
        # xml_content = '<?xml version=\'1.0\'?>\n' + new_content
        # 保存到文件
        # with open(self.xml_file_path, 'w', encoding='UTF-8') as file:
        #     file.write(xml_content)

    def print_info(self):
        # print(self.root.tag)
        # Print Namespace
        for ns in self.nsmap:
            print(f"Namespace prefix: {ns}, URI: {self.nsmap[ns]}")
        
        # for elem in self.elems:
        #     print(elem.get("name"))

# Main Function
if __name__ == "__main__":
    xdm_parser = gl0906_xml_parser(can_xdm_file_path)
    xdm_parser.print_info()
    xdm_parser.handle_can_hwobj_elements()

    can_msg_parse = cmt.gl0906_can_parse()
    can_msg_parse.find_and_parse_can_comm_matrix_file()
    can_msg_parse.find_and_parse_can_pdur_table()
    # can_msg_parse.print_can_matrix_by_send_type()
    can_msg_parse.generate_can_hw_obj_filter()
    xdm_parser.handle_can_hwobj_filter_elements(can_msg_parse.can_hw_obj_filter)
    xdm_parser.write_xml()